#include "JVersionRepository.h"
#include "MultipleTreeNode.h"
#include "Convert.h"
#include "JRepositoryConfig.h"
#include "JDefine.h"
#include "JRepositoryOperationResult.h"
#include "JVerifyValidate.h"
#include "JException.h"
#include "JInOutPutFstream.h"
#include "JUuid.h"


JVersionRepository::JVersionRepository() 
{
    MultipleTreeNodeCompareFilePath* pCompare = new MultipleTreeNodeCompareFilePath();
    pTree = new MultipleTree<string,VersionRepositoryNodeData>(*pCompare);
    listPVersion.push_back(this);
}

JVersionRepository::~JVersionRepository() 
{
    
}
    
JRepositoryOperationResult JVersionRepository::Add(JFile& _file)
{
    return Add(_file,"file");
}

JRepositoryOperationResult JVersionRepository::Add(JDir& _dir)
{
    return Add(_dir,"dir");
}

JRepositoryOperationResult JVersionRepository::Add(JBaseFile& _baseFile,string fileOrDir)
{
    string key = GenerateRelativePath(versionID,_baseFile.filename);
    JRepositoryOperationResult result;
    //这里的filename都是相对路径
    if(!IsExist(key))
    {
        //把上一个版本中的节点复制到本版本中。
        CopyFromPreviousVersion(key);
        //处理本节点
        VersionRepositoryNodeData data(_baseFile,fileOrDir);
        MultipleTreeNode<string,VersionRepositoryNodeData> node(key,data,NULL);
        AddToTree(node,_baseFile);
        //如果是文件，那么添加文件
        
        result.result = JRepositoryOperationResult_Success;
        result.message = "Add node success.";
    }
    else
    {
        result.result = JRepositoryOperationResult_AlreadyOper;
        result.message = "Already exist the node.";
    }
    return result;
}

JRepositoryOperationResult JVersionRepository::CopyFromPreviousVersion(std::string _relativePath)
{
    std::list<std::string> ancestorFileName = JBaseFile::GenerateAncestor(_relativePath);
    std::list<std::string>::iterator ite = ancestorFileName.begin();
        //处理完所有的祖先节点
        for(;ite != ancestorFileName.end(); ++ite)
        {
            std::cout << "*Ite" << *ite << std::endl;
            std::pair<FindFlag,MultipleTreeNode<std::string,VersionRepositoryNodeData>* > flag = pTree->FindRealPlace(*ite);
            if(flag.first == FindNode)
            {
                continue;
            }
            else if(flag.first == FindAncestorNode)
            {
                //第一步，查看这个节点的data信息中是否有信息
                //得到了上一级目录，在目录的data中查好是否有现在处理的父目录*ite存在
                std::list<VersionRepositoryNodeDataItem>& items = flag.second->data.listItem;
                std::list<VersionRepositoryNodeDataItem>::iterator ite2 = items.begin();
                for(;ite2 != items.end(); ++ite2)
                {
                    std::pair<int,std::string> pp = SplitRelativePath(ite2->relativeFullFileName);
                    std::pair<int,std::string> pp2 = SplitRelativePath(*ite);
                    //如果存在
                    if(pp.second == pp2.second)
                    {
                        //得到需要的版本
                         JVersionRepository* pRepos = GetListPVersion(pp.first);
                         string otherKey = JBaseFile::ModifyPath(*ite,1,Convert::ToString(pp.first));
                         std::pair<FindFlag,MultipleTreeNode<string,VersionRepositoryNodeData>* > nodePair = pRepos->pTree->FindRealPlace(otherKey);
                         if(nodePair.first == FindNode)
                         {
                             //这里是拷贝上一个版本的节点，所以这里实际上第二个参数没用
                             JBaseFile baseFile;
                             AddToTree(*nodePair.second,baseFile);
                          }
                          break;
                     }
                        
                }
            }
            /////////////////////////////////////////////////
        }
    --ite;
    JRepositoryOperationResult result;
    //把添加所有的目录中，返回最低级的目录
    result.result = JRepositoryOperationResult_Success;
    result.message = *ite;
    return result;
}


JVersionRepository* JVersionRepository::GetListPVersion(int _versionID)
{
    std::list<JVersionRepository*>::iterator ite = listPVersion.begin();
    for(;ite != listPVersion.end(); ++ite)
    {
        if((*ite)->versionID == _versionID)
        {
            return *ite;
        }
    }
    //没有找到，那么读取版本，然后再返回
    JVersionRepository* pRepos = OpenAVersion(_versionID);
    listPVersion.push_back(pRepos);
    return pRepos;
}

JRepositoryOperationResult JVersionRepository::Delete(JBaseFile& _baseFile,string fileOrDir)
{
    string key = GenerateRelativePath(versionID,_baseFile.filename);
    if(!IsExist(key))
    {
        //把上一个版本中的节点复制到本版本中。
        JRepositoryOperationResult result;
        result = CopyFromPreviousVersion(key);
        //得到最低级的目录名称
        string upRelativePath = "";
        if(result.result == JRepositoryOperationResult_Success)
        {
            string s = result.message;
            upRelativePath = JBaseFile::ModifyPath(s,1,Convert::ToString(versionID));
        }
        std::pair<FindFlag,MultipleTreeNode<string,VersionRepositoryNodeData>* > flag = this->pTree->FindRealPlace(upRelativePath,NULL);
        if(flag.first == FindNode)
        {
            VersionRepositoryNodeDataItem item;
            item.relativeFullFileName = key;
            flag.second->data.listItem.remove(item);
        }
    }
    JRepositoryOperationResult result;
    return result;
}

JRepositoryOperationResult JVersionRepository::Delete(JFile& _file)
{
    return Delete(_file,"file");
}

JRepositoryOperationResult JVersionRepository::Delete(JDir& _dir)
{
    return Delete(_dir,"dir");
}
 
JRepositorySearchResult JVersionRepository::Search(string _fileName)
{
    JRepositorySearchResult result;
    string relativeFileName = GenerateRelativePath(versionID,_fileName);
    std::list<std::string> ancestorFileName = JBaseFile::GenerateAncestor(relativeFileName);
    //上面的ancestorFileName只有父目录，需要加入当前目录
    ancestorFileName.push_back(relativeFileName);
    std::list<std::string>::iterator ite = ancestorFileName.begin();
    JVersionRepository* pVersionRepos = this;
    for(;ite != ancestorFileName.end(); ++ite)
    {
        string tmpRelativeFileName = ModifyVersionPath(pVersionRepos->versionID,*ite);
        std::pair<FindFlag, MultipleTreeNode<string, VersionRepositoryNodeData>* > flag = pVersionRepos->pTree->FindRealPlace(tmpRelativeFileName);
        if (flag.first == FindNode)
        {
            //找到了这个节点
            if(_fileName == SplitRelativePath(tmpRelativeFileName).second)
            {
                AddToSearchResult(result,flag.second->data);
            }
            //找到了这个节点的父节点
            else
            {
                continue;
            }
        }
        //因为是一个节点一个节点查找的，所以这个节点中的data.listItem中一定有这个节点的信息，否则就没有这个节点
        else if(flag.first == FindAncestorNode)
        {
            pair<int,string> p = flag.second->data.GetListItem(tmpRelativeFileName);
            if(p.first != -1)
            {
                pVersionRepos = GetListPVersion(p.first);
                --ite;
            }
            //没有这个节点
            else
            {
                break;
            }
        }
        else
        {
            break;
        }
    }
    return result;
//    std::pair<FindFlag,MultipleTreeNode<string,VersionRepositoryNodeData>* > flag = this->pTree->FindRealPlace(relativeFileName,NULL);
//    if(flag.first == FindNode)
//    {
//        result.fileOrDir = flag.second.data.fileOrDir;
//        //如果找到的是文件
//        if(result.fileOrDir == "file")
//        {
//            JFile tmpFile(flag.second.data.baseFile);
//            result.listFile.push_back(tmpFile);
//        }
//        //如果找到的是目录
//        else
//        {
//            std::list<VersionRepositoryNodeDataItem>::iterator ite = flag.second.data.listItem;
//            for(;ite != flag.second.data.listItem.end(); ++ite)
//            {
//                if((*ite)->fileOrDir == "file")
//                {
//                    JFile file;
//                    GetBaseFileInfoByRelativeFileName((*ite)->relativeFullFileName,file);
//                    result.listFile.push_back(file);
//                }
//                else if((*ite)->fileOrDir == "dir")
//                {
//                    JDir dir;
//                    GetBaseFileInfoByRelativeFileName((*ite)->relativeFullFileName,dir);
//                    result.listDir.push_back(dir);
//                }
//            }
//        }
//    }
//    else if(flag.first == FindAncestorNode)
//    {
//        std::list<std::string> ancestorFileName = JBaseFile::GenerateAncestor(relativeFileName);
//        std::list<std::string>::iterator ite2 = ancestorFileName.begin();
//        JVersionRepository* pVersionRepos = this;
//        for(;ite2 != ancestorFileName.end(); ++ite2)
//        {
//             std::pair<FindFlag,MultipleTreeNode<string,VersionRepositoryNodeData>* > flag2 = pVersionRepos->pTree->FindRealPlace(*ite2);
//             if(flag2.first == Fin)
////            if(*ite2 == flag.second.key)
////            {
////                ++ite2;
////                string s = *ite2;
////                //p.first是所处的版本号，string是相应的_relativeFileName
////                pair<int,string> p = flag.second.data.GetListItem(s);
////                if(p.first != -1)
////                {
////                    JVersionRepository* pVersionRepos = GetListPVersion(p.first);
////                    pVersionRepos->pTree->FindRealPlace(p.second);
////                }
////                //////////////////////////
////                --ite2;
////            }
//        }
//    }
}

JRepositoryOperationResult JVersionRepository::Modify(JFile& _file1,JFile& _file2)
{
    JRepositoryOperationResult result;
    Delete(_file1);
    Add(_file2);
    return result;    
}

JRepositoryOperationResult JVersionRepository::Modify(JDir& _dir1,JDir& _dir2)
{
    JRepositoryOperationResult result;
    Delete(_dir1);
    Delete(_dir2);
    return result;    
}

JRepositoryOperationResult JVersionRepository::CreateAVersion(int _versionID)
{
    versionID = _versionID;
    //读取上一个版本的信息，并且只有createAversion的时候才会读取上一个版本信息
    if(versionID != 0)
    {
        OpenPreviousVersion(versionID - 1);
    }
    //添加repos节点
    std::string strPath = JRepositoryConfig::repositoryRelativePath;
    //VersionRepositoryNodeData data;
    MultipleTreeNode<string,VersionRepositoryNodeData> node;
    node.key = strPath;
    node.data.fileOrDir = "dir";
    JBaseFile _baseFile;
    AddToTree(node,_baseFile);
    //pTree->Add(strPath,data,NULL);
    //添加repos/1节点，添加这个节点时，如果是versionID=0，那么直接添加；如果versionID!=0，那么从上个版本复制
    std::string strPath2 = GenerateRelativePath(versionID,"");
    MultipleTreeNode<string,VersionRepositoryNodeData> node2;
    if(versionID == 0)
    {
        node2.key = strPath2;
        node2.data.fileOrDir = "dir";
            AddToTree(node2,_baseFile);
    }
    else
    {
        std::string strPath3 = GenerateRelativePath(versionID - 1,"");
        std::pair<FindFlag,MultipleTreeNode<string,VersionRepositoryNodeData>* > nodePair = pPreviousVersion->pTree->FindRealPlace(strPath3);
        if(nodePair.first == FindNode)
        {
            AddToTree(*(nodePair.second),_baseFile);
        }
    }
    //VersionRepositoryNodeData data2;
    //MultipleTreeNode<string,VersionRepositoryNodeData>* pNode = pTree->Add(strPath2,data2,NULL);
    JRepositoryOperationResult result;
    return result;
}

JRepositoryOperationResult JVersionRepository::ReadTheVersion(int _versionID)
{
    versionID = _versionID;
    JRepositoryOperationResult result;
    InitiativeReSerialize(_versionID);
    return result;
}

bool JVersionRepository::IsExist(string _relativeFilePath)
{
    std::pair<FindFlag,MultipleTreeNode<std::string,VersionRepositoryNodeData>* > flag = pTree->FindRealPlace(_relativeFilePath);
    if(flag.first == mylib::FindNode)
    {
        return true;
    }
    return false;
}

JVersionRepository* JVersionRepository::OpenPreviousVersion(int _versionID)
{
    pPreviousVersion = OpenAVersion(_versionID);
    return pPreviousVersion;
}

JVersionRepository* JVersionRepository::OpenAVersion(int _versionID)
{
    JVersionRepository * pRepos = new JVersionRepository();
    pRepos->ReadTheVersion(_versionID);
    return pRepos;
}

std::string JVersionRepository::GenerateRelativePath(int _versionID,std::string s)
{
    return JRepositoryConfig::repositoryRelativePath + PATH_SPLIT + Convert::ToString(_versionID) + s;
}

JRepositoryOperationResult JVersionRepository::AddToTree(MultipleTreeNode<string,VersionRepositoryNodeData>& _node,JBaseFile& _baseFile)
{
    JRepositoryOperationResult result;
    MultipleTreeNode<string,VersionRepositoryNodeData>* pNode = pTree->Add(ModifyVersionPath(versionID,_node.key),_node.data);
    //如果是文件，那么创建文件
    string fileName = "";
    if(pNode->data.fileOrDir == "file")
    {
        string rootPath = JRepositoryConfig::repositoryRootPath;
        string versionDir = rootPath + PATH_SPLIT + Convert::ToString(versionID);
        fileName = versionDir + PATH_SPLIT + JUuid::ToString();
        if(!JDir::IsExist(versionDir))
        {
            JDir::CreateDir(versionDir);
        }
        JBaseFile::CopyBaseFile(((JFile&)_baseFile).tempFileName,fileName);
        pNode->data.convertedFileName = fileName;
    }
    //更新父节点的信息
    MultipleTreeNode<string,VersionRepositoryNodeData>* pParent = pNode->pParent;
    if(pParent != NULL)
    {
        VersionRepositoryNodeDataItem item(pNode->key,pNode->data.fileOrDir);
        //如果是文件，需要把convertedFileName也要修改
        item.convertedFileName = fileName;
        AddOrUpdateData(pParent,item);
    }
    return result;
}

string JVersionRepository::ModifyVersionPath(int _versionID, std::string s)
{
    return JBaseFile::ModifyPath(s,1,Convert::ToString(_versionID));
}

void JVersionRepository::AddOrUpdateData(MultipleTreeNode<string,VersionRepositoryNodeData>* pParent, VersionRepositoryNodeDataItem& _item)
{
    std::list<VersionRepositoryNodeDataItem>::iterator ite = pParent->data.listItem.begin();
    for(;ite != pParent->data.listItem.end(); ++ite)
    {
        if(JBaseFile::ModifyPath((*ite).relativeFullFileName,1,Convert::ToString(versionID)) == _item.relativeFullFileName)
        {
            *ite = _item;
            break;
        }
    }
    if(ite == pParent->data.listItem.end())
    {
        pParent->data.listItem.push_back(_item);
    }
}

void JVersionRepository::AddNodeSuccessEvent(MultipleTreeNode<std::string,VersionRepositoryNodeData>* pNode)
{
    VersionRepositoryNodeDataItem item(pNode->key,pNode->data.fileOrDir);
    pNode->pParent->data.listItem.push_back(item);
}

int JVersionRepository::Serialize(JInOutPut& strea, int& allSize)
{
    int classSize = 0,selfSize = 0;
    JSerialize::SerializeHead(strea,selfSize,classSize);
    JSerialize::Serialize(strea,versionID,classSize);
    pTree->Serialize(strea,classSize);
    return JSerialize::SerializeTail(strea,allSize,selfSize,classSize);
}

int JVersionRepository::ReSerialize(JInOutPut& strea)
{
    int classSize = JSerialize::ReSerializeHead(strea);
    versionID = JSerialize::ReSerializeInt(strea);
    pTree->ReSerialize(strea);
    return classSize;
}

int JVersionRepository::InitiativeSerialize()
{
    std::string rootPath = JRepositoryConfig::repositoryRootPath;
    std::string versionDir = rootPath + PATH_SPLIT + Convert::ToString(versionID);
    if(!JDir::IsExist(versionDir))
    {
        JDir::CreateDir(versionDir);
    }
    std::string versionReposPath = versionDir + PATH_SPLIT + "VersionRepositoryInfo";
    if(!JFile::IsExist(versionReposPath))
    {
        JFile::CreateFile(versionReposPath);
    }
    JInOutPutFstream strea(versionReposPath);
    strea.OpenStream(ios::binary | ios::trunc | ios::out);
    int allSize = 0;
    Serialize(strea,allSize);
    strea.CloseStream();
    return allSize;
}

int JVersionRepository::InitiativeReSerialize(int _versionID)
{
    std::string rootPath = JRepositoryConfig::repositoryRootPath;
    std::string versionDir = rootPath + PATH_SPLIT + Convert::ToString(_versionID);
    std::string versionReposPath = versionDir + PATH_SPLIT + "VersionRepositoryInfo";
    JInOutPutFstream strea(versionReposPath);
    strea.OpenStream(ios::binary | ios::in);
    int classSize = ReSerialize(strea);
    strea.CloseStream();
    return classSize;
}

std::pair<int,std::string> JVersionRepository::SplitRelativePath(std::string _relativePath)
{
    std::list<std::string> listStr = JBaseFile::SplitPath(_relativePath);
    int _versionID = 0;
    std::string fileName = "";
    std::list<std::string>::iterator ite = listStr.begin();
    int index = 0;
    for(;ite != listStr.end(); ++ite)
    {
        if(index == 1)
        {
            _versionID = Convert::ToInt(*ite);
        }
        else if(index > 1)
        {
            fileName += (PATH_SPLIT + *ite);
        }
        ++index;
    }
    return make_pair<int,std::string>(_versionID,fileName);
}

void JVersionRepository::AddToSearchResult(JRepositorySearchResult& _result,VersionRepositoryNodeData& _data)
{
    _result.fileOrDir = _data.fileOrDir;
    if(_data.fileOrDir == "file")
    {
        JFile file;
        GetBaseFileInfoByData(_data,file);
        _result.listFile.push_back(file);
    }
    else
    {
        std::list<VersionRepositoryNodeDataItem>::iterator ite = _data.listItem.begin();
        for(;ite != _data.listItem.end(); ++ite)
        {
            if(ite->fileOrDir == "file")
            {
                JFile file;
                file.filename = SplitRelativePath(ite->relativeFullFileName).second;
                _result.listFile.push_back(file);
            }
            else
            {
                JDir dir;
                dir.filename = SplitRelativePath(ite->relativeFullFileName).second;
                _result.listDir.push_back(dir);
            }
        }
    }
}

void JVersionRepository::GetBaseFileInfoByData(VersionRepositoryNodeData& data,JBaseFile& _baseFile)
{
    _baseFile = data.baseFile;
}

std::pair<int,string> VersionRepositoryNodeData::GetListItem(string _relativeFileName) 
{
    string s = JVersionRepository::SplitRelativePath(_relativeFileName).second;
    std::list<VersionRepositoryNodeDataItem>::iterator ite = listItem.begin();
    int i = listItem.size();
    for (; ite != listItem.end(); ++ite) 
    {
        pair<int, string> p = JVersionRepository::SplitRelativePath(ite->relativeFullFileName);
        if (p.second == s) 
        {
            return p;
        }
    }
    return make_pair<int, string > (-1, "");
}